/*
 * Copyright (c) 2022 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include "board.h"
#include "hpm_clock_drv.h"
#include "hpm_uart_drv.h"
#ifdef HPMSOC_HAS_HPMSDK_DMAV2
#include "hpm_dmav2_drv.h"
#else
#include "hpm_dma_drv.h"
#endif
#include "hpm_dmamux_drv.h"
#include "hpm_l1c_drv.h"
#include "hpm_common.h"

#define TEST_UART                   HPM_UART10
#define TEST_UART_CLK_NAME          clock_uart10
#define TEST_UART_TX_DMA_REQ        HPM_DMA_SRC_UART10_TX
#define TEST_UART_RX_DMA_REQ        BOARD_CONSOLE_UART_RX_DMA_REQ

#define TEST_UART_DMA_CONTROLLER    BOARD_APP_HDMA
#define TEST_UART_DMAMUX_CONTROLLER BOARD_APP_DMAMUX
#define TEST_UART_TX_DMA_CHN        (0U)
#define TEST_UART_RX_DMA_CHN        (1U)
#define TEST_UART_TX_DMAMUX_CHN     DMA_SOC_CHN_TO_DMAMUX_CHN(TEST_UART_DMA_CONTROLLER, TEST_UART_TX_DMA_CHN)
#define TEST_UART_RX_DMAMUX_CHN     DMA_SOC_CHN_TO_DMAMUX_CHN(TEST_UART_DMA_CONTROLLER, TEST_UART_RX_DMA_CHN)
#define TEST_UART_DMA_IRQ           BOARD_APP_HDMA_IRQ

#define TEST_BUFFER_SIZE   (16U)
ATTR_PLACE_AT_NONCACHEABLE uint8_t uart_buff[TEST_BUFFER_SIZE];

char transfer_data[12] = {"zlg is good\r\n"};
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(8) dma_linked_descriptor_t descriptors[2];

void uart_dma_transfer(void)
{
    dma_channel_config_t ch_config = {0};

    dma_reset(HPM_HDMA);
    
    dma_default_channel_config(HPM_HDMA,&ch_config);

    ch_config.src_addr = core_local_mem_to_sys_address(HPM_CORE0,((uint32_t)(&transfer_data[0])));//原地址
    ch_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, ((uint32_t)(&TEST_UART->THR)));//目的地址
    ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;//一次搬运几次数据
    ch_config.src_width = DMA_TRANSFER_WIDTH_BYTE;//数据宽度
    ch_config.dst_width = DMA_TRANSFER_WIDTH_BYTE;
    ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;//目的地址地址自增
    ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;//原地址的地址不自增
    ch_config.src_mode      = DMA_HANDSHAKE_MODE_NORMAL;//搬运完成后，回发信号告知DMA，使能该值时，DMA搬运频率才受PWM频率控制。
    ch_config.dst_mode      = DMA_HANDSHAKE_MODE_HANDSHAKE;
    ch_config.size_in_byte  = sizeof(transfer_data);

    ch_config.linked_ptr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&descriptors[0]);

    if(status_success != dma_config_linked_descriptor(HPM_HDMA,&descriptors[0],0, &ch_config))//该描述符连接自身
    {
        printf("dma config linked descriptor failed\r\n");
        return; 
    }
    if(status_success != dma_setup_channel(HPM_HDMA,0,&ch_config,true))
    {
        printf("dma setup channel failed\r\n");
        return;
    }
    printf("dma setup channel done\r\n");
}

int main(void)
{
    hpm_stat_t stat;
    uart_config_t config = {0};

    board_init();
    
    HPM_IOC->PAD[IOC_PAD_PD24].FUNC_CTL = IOC_PD24_FUNC_CTL_UART10_TXD;
    HPM_IOC->PAD[IOC_PAD_PD25].FUNC_CTL = IOC_PD25_FUNC_CTL_UART10_CTS;

    /* if TEST_UART is same as BOARD_CONSOLE_BASE, it has been initialized in board_init(); */
    board_init_uart(TEST_UART);

    uart_default_config(TEST_UART, &config);
    config.fifo_enable = true;
    config.dma_enable = true;
    config.src_freq_in_hz = clock_get_frequency(TEST_UART_CLK_NAME);
    config.tx_fifo_level = uart_tx_fifo_trg_not_full;
    config.rx_fifo_level = uart_rx_fifo_trg_not_empty;
    config.modem_config.auto_flow_ctrl_en = true;/* 使能自动硬件流控 */
    config.modem_config.set_rts_high = false;/* uart10在本例程中，仅作为发送方，所以置rts无关紧要 */
    stat = uart_init(TEST_UART, &config);
    if (stat != status_success) {
        printf("failed to initialize uart\n");
        while (1) {
        }
    }

    uart_modem_enable_auto_flow_control(TEST_UART);
    intc_m_enable_irq_with_priority(TEST_UART_DMA_IRQ, 1);

    dmamux_config(TEST_UART_DMAMUX_CONTROLLER, TEST_UART_RX_DMAMUX_CHN, TEST_UART_RX_DMA_REQ, true);
    dmamux_config(TEST_UART_DMAMUX_CONTROLLER, TEST_UART_TX_DMAMUX_CHN, TEST_UART_TX_DMA_REQ, true);

    uart_dma_transfer();

    while (1) {

    }
    return 0;
}
